package com.wanban.download.runnable

import android.util.Log
import com.wanban.download.utils.OkHttpClientUtils
import com.wanban.download.WBDownloadUtils
import com.wanban.download.base.BaseDownloadInterface
import com.wanban.download.listener.OnFileDownloadListener
import com.wanban.download.utils.DownloadConstants
import okhttp3.Request
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.InputStream
import java.io.RandomAccessFile

class SingleThreadDownloadSingleFileUtils(
    private val url: String,
    private val filePath: String,
    private val listener: OnFileDownloadListener?,
    private val header: Map<String, String?>? = null,
    private var startPosition: Long = 0L,
    private var endPosition: Long = 0L,
    private var tag: String? = null
): BaseDownloadInterface(true) {

    private var totalLength = -1L
    // 时间间隔，纳秒
    private var randomAccessFile: RandomAccessFile? = null
    private var fileOutputStream: FileOutputStream? = null
    private var bufferOutputStream: BufferedOutputStream? = null
    // 是否多线程下载
    private val isUserRandomAccess by lazy { endPosition > 0 && startPosition >= 0 }


    /**
     * 返回下载的Runnable
     */
    fun getDownloadRunnable(): Runnable {
        isInterrupted = false
        cancelProgress()
        intervalTime = 0L
        currentDownloadSpeed = 0
        currentDownloadLength = 0
        // 执行单线程下载
        val runnable = Runnable {
            listener?.onStart(url)
            val request = Request.Builder().url(url)
            header?.keys?.forEach { key ->
                val value = header[key]
                if (value != null) {
                    request.addHeader(key, value)
                }
            }
            if (isUserRandomAccess) {
                request.addHeader("RANGE", "bytes=${startPosition}-${endPosition}")
            }
            val response = OkHttpClientUtils.openSync(request.build())
            if (response == null) {
                listener?.onError(url, DownloadConstants.ERROR_HTTP_REQUEST_ERROR)
                return@Runnable
            }
            if (response.isSuccessful) {
                totalLength = if (isUserRandomAccess) {
                    endPosition - startPosition
                } else {
                    response.body?.contentLength()?:0L
                }
                val inputStream = response.body?.byteStream()
                if (inputStream == null) {
                    listener?.onError(url, DownloadConstants.ERROR_HTTP_REQUEST_ERROR)
                    return@Runnable
                }
                writeResponseBodyToDiskSingleThread(inputStream)
            } else {
                listener?.onError(url, DownloadConstants.ERROR_HTTP_REQUEST_ERROR)
            }
        }
        return runnable
    }

    override fun startDownload(totalLength: Long) {
        if (executors.isTerminated || executors.isShutdown) {
            isInterrupted = true
            return
        }
        executors.submit(getDownloadRunnable())
        intervalTime = 1000L
        startProgressCallback()
    }

    override fun onProgressCallback() {
        if (isInterrupted) return
        val percent = currentDownloadLength * 1f / totalLength
        listener?.onProgress(url, currentDownloadSpeed, currentDownloadLength, percent)
        currentDownloadSpeed = 0
    }

    // 单线程写入文件
    private fun writeResponseBodyToDiskSingleThread(inputStream: InputStream) {
        val outputFile = File(filePath)
        if (!outputFile.exists()) {
            if (!outputFile.createNewFile()) {
                throw FileNotFoundException()
            }
        }
        var byteReadLength: Int
        val data = ByteArray(4096)
        // 是否使用RandomAccess写入文件
        if (isUserRandomAccess) {
            randomAccessFile = RandomAccessFile(filePath, "rw")
            randomAccessFile?.seek(startPosition)
        } else {
            fileOutputStream = FileOutputStream(outputFile)
            bufferOutputStream = BufferedOutputStream(fileOutputStream)
        }
        while ((inputStream.read(data).also { byteReadLength = it }) != -1) {
            if (isInterrupted) break
            if (isUserRandomAccess) {
                randomAccessFile?.write(data, 0, byteReadLength)
            } else {
                bufferOutputStream?.write(data, 0, byteReadLength)
            }
//            if (startPosition == 0L && currentLength >= totalLength / 2) {
//                throw NullPointerException("测试")
//            }
            currentDownloadLength += byteReadLength
            if (intervalTime <= 0) { // 多线程下载的时候需要
                val percent = currentDownloadLength * 1f / totalLength
                listener?.onProgress(url, byteReadLength.toLong(), currentDownloadLength, percent)
            } else { // 单线程下载由onProgressCallback控制
                currentDownloadSpeed += byteReadLength
            }
        }
        if (totalLength < 0) {
            if (isInterrupted) return
            cancel()
            listener?.onComplete(url, currentDownloadLength, filePath)
            return
        }
        if (currentDownloadLength == totalLength) {
            if (isInterrupted) return
//            if (endPosition > 0) {
//                Log.d(WBDownloadUtils.TAG, "$tag -> 下载完成 -> start - end: $startPosition - $endPosition")
//            } else {
//                Log.d(WBDownloadUtils.TAG, "$tag -> 下载完成: $currentDownloadLength")
//            }
            cancel()
            listener?.onComplete(url, currentDownloadLength, filePath)
        } else {
            if (endPosition > 0) {
                Log.d(WBDownloadUtils.TAG, "$tag -> 下载完成后与指定文件大小不一致 -> start - end: $startPosition - $endPosition")
            } else {
                Log.d(WBDownloadUtils.TAG, "$tag -> 下载完成后与指定文件大小不一致")
            }
            if (isInterrupted) return
            cancel()
            listener?.onError(url, DownloadConstants.ERROR_CANNOT_DOWNLOAD_TO_DELETE)
        }
    }
}